// es6 -- wx public.js
// 作者 王欢
// 开始日期 2019-12-20
// 前言 -- 更新以前es5的公用脚本。
const { $copy , $toClass ,$trimAll } = require("./common");
const { $url , $back  } = require("./url");
const { $request , $get , $post , $put , $delete } = require("./http");
const { $log ,$alert , $confirm , $fail } = require("./layer");
const { $to } = require("./await_to");
// 正则验证字典
const $regExp = {
    phone: /^1[3456789]\d{9}$/,
    email: /^([A-Za-z0-9_\-.])+@([A-Za-z0-9_\-.])+\.([A-Za-z]{2,4})$/,
    pass: /^[A-Za-z0-9]{6,20}$/,
    realName: /^[\u4E00-\u9FA5\uf900-\ufa2d·s]{2,20}$/,
    ID: /^[1-9][0-9]{5}(19|20)[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|31)|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}([0-9]|x|X)$/
}


// 绘制验证码
// 绘制尺寸  支持  px 与 rpx
// 参数字典
/* opts={
    // 指定绘制类型
    // 默认全部  包括 数字[0-9] 英文 [a-zA-Z]  
    type, // String -> "all" | "number" |  "string"
    // 指定绘制 value 
    value, // String length == 4
    width, // Number || String #requird -> 100 |  "100px" | "100rpx"  
    height, // 同上
    // 绘制canvas id
    id, // String #requird
}   
    函数返回一个 value值  作为判断
*/
// 示例
/* 
    page({
        drawInfo:{
            id:"canvas",
            width: "100px",
            height: "50px",
            type:"number"
            // value: "1205"
        },
        drawCav(){
            this.$drawCode(this.data.drawInfo, (res) => {
                this.setData({
                    drawVal: res
                })
            });
        },
        onLoad: function (options) {
            this.drawCav();
        },
    })

    <view>
        <canvas
            style="width:{{ drawInfo.width }};height:{{ drawInfo.height }};"  
            canvas-id="{{ drawInfo.id }}" 
            bindtap="drawCav"
        ></canvas>
    </view>
    <view>{{ drawVal }}</view>

*/

// 返回一个随机数
/* 
   _randomNum(min:Number, max:Number);  
*/
function _randomNum(min, max) {
    return Math.floor(Math.random() * (max - min) + min);
}
// 返回一个随机色
/* 
    _randomColor(min:Number, max:Number);  
*/
function _randomColor(min, max) {
    let r = _randomNum(min, max),
        g = _randomNum(min, max),
        b = _randomNum(min, max);
    return `rgb(${r},${g},${b})`;
}
/* 
    返回一个绘制字符串
    可以在 suc 第一个参数拿到 绘制字符串 执行回调函数
    $drawCode(opts:Object[, suc:Function]);
*/
function $drawCode(opts, suc) {
    // 参数合并 类型判断
    let defaultOpts = {
        type: "all",
    };
    if (opts && $toClass(opts) == "Object") {
        // 获取 id 宽高
        let { id, width, height } = $copy(defaultOpts, opts);
        if (id && width && height) {
            let canVal;
            let drawData;
            let ctx = uni.createCanvasContext(id);
            // 如果value参数没有  最常见的情况
            let { type, value } = defaultOpts;
            // 判断value 转换一组渲染字符串数组
            let filterData = function (str, rdm = true) {
                let data = [];
                if (rdm) {
                    let len = str.length - 1;
                    for (let i = 0; i < 4; i++) {
                        let key;
                        data.push(
                            str[_randomNum(0, len)]
                        );
                    }
                } else {
                    data = Array.prototype.slice.call(str);
                }
                return data;
            };
            // 根据类型获取绘制数组
            // 没有指定value存在的情况
            if (!value) {
                let codeData = [
                    'abcefghjklmnpqrstwxyABCEFGHJKLMNPQRSTWXY',
                    '0123456789'
                ];
                let sliceData;
                if (type == "all") {
                    sliceData = codeData.join("");
                } else if (type == "number") {
                    sliceData = codeData[1];
                } else if (type == "string") {
                    sliceData = codeData[0];
                } else {
                    throw new Error("the type is must be all,number or string")
                }
                drawData = filterData(sliceData);
                // 有指定value
            } else {
                if (value && typeof value == "string" && value.length == 4) {
                    drawData = filterData(value, false);
                } else {
                    throw new Error("the value params type must be string and length == 4");
                }
            }
            // 判断 width 或者 height是否存在rpx单位
            // 有则根据 缩放比例计算实际宽高

            let scale = 1;
            if ((width + height).search("rpx") != -1) {
                let { windowWidth } = uni.getSystemInfoSync();
                scale = windowWidth / 750;
            }
            // 暂且只支持整数
            // 根据缩放比例重新计算宽高尺寸
            let scaleSize = function (size) {
                let num = parseInt(size);
                if (size.search("rpx") != -1) {
                    return num * scale;
                }
                return num;
            };
            let drawWidth = scaleSize(width);
            let drawHeight = scaleSize(height);
            /**绘制背景色**/
            //颜色若太深可能导致看不清
            ctx.fillStyle = _randomColor(180, 240);
            ctx.fillRect(0, 0, drawWidth, drawHeight)
            /**绘制文字**/
            for (let i = 0; i < 4; i++) {
                let ti = drawData[i],
                    x = drawWidth / 4 / 10 + i * (drawWidth / 4),
                    y = _randomNum(drawHeight - drawHeight / 5, drawHeight - drawHeight / 10),
                    deg = _randomNum(-20, 20);
                ctx.fillStyle = _randomColor(50, 120); //随机生成字体颜色
                ctx.font = _randomNum(20, drawHeight) + 'px SimHei'; //随机生成字体大小
                //修改坐标原点和旋转角度
                let transX = i ? x :0;
                ctx.translate(transX, y);
                ctx.rotate(deg * Math.PI / 180);
                ctx.fillText(ti, drawWidth / 4 / 4, 0);

                //恢复坐标原点和旋转角度
                ctx.rotate(-deg * Math.PI / 180);
                ctx.translate(-transX, -y);
                // /**绘制干扰线**/
                ctx.strokeStyle = _randomColor(120, 230);
                ctx.beginPath();
                ctx.moveTo(_randomNum(0, drawWidth), _randomNum(0, drawHeight));
                ctx.lineTo(_randomNum(0, drawWidth), _randomNum(0, drawHeight));
                ctx.stroke();
                canVal += ti;
            }
            // /**绘制干扰点**/
            for (let j = 0; j < 10; j++) {
                ctx.fillStyle = _randomColor(0, 255);
                ctx.beginPath();
                ctx.arc(_randomNum(0, drawWidth), _randomNum(0, drawHeight), 1, 0, 2 * Math.PI);
                ctx.fill();
            }
            // 绘制完成
            ctx.draw();
            // 返回 绘制字符串
            let drawStr = drawData.join("");
            suc && typeof suc == "function" && suc(drawStr);
            return drawStr;

        } else {
            throw new ReferenceError("missing necessary parameters");
        }
    } else {
        throw new Error("the opts must be required or type is Object");
    }
}
/* 
    数字格式化
    _checkTime(i:Number);
*/
function _checkTime(i) {
	return i < 10 && i >= 0 ? '0' + i : i;
};

/* 
    
    // 计算剩余时间 
    // 如果有剩余时间  则返回一个数组 分别是  [天数,小时,分钟,秒数] 
    $leftDate(opts:String|DateObject[,clearDays:Boolean]);
    返回值
       -- 如果传入的时间  大于等于当前的时间
       返回{
            d // 天数
            ,h // 小时
            ,m // 分钟
            ,s // 秒
            ,code:[ d,h,m,s ] 
            //如果第二个参数为 true  且时间差为24小时以内 返回 
            [h,m,s]
       }
     -- 小于当前时间  返回  false      
*/

function $leftDate( dateParams , clearDays = false ){
    if( dateParams  !== undefined){
        const paramsType = typeof dateParams;
        let endDate = null;
        if( paramsType === "string" ){
            endDate = new Date( dateParams );
        }else if( paramsType === "object" ){
            endDate = dateParams;
        }else{
            throw TypeError("the params type must be String or DateObject");
        }
        const leftTimes = endDate.getTime() - new Date().getTime();
        if( leftTimes >= 0 ){
            const leftDays = _checkTime(  parseInt( leftTimes / 1000 / 60 / 60 / 24 ) );
            const leftHours = _checkTime( parseInt( leftTimes / 1000 / 60 / 60 % 24 ) );
            const leftMinutes = _checkTime( parseInt( leftTimes / 1000 / 60 % 60 ) );
            const leftSeconds = _checkTime( parseInt( leftTimes / 1000 % 60 ) );
            const code = [ leftDays , leftHours , leftMinutes , leftSeconds ];
            if( clearDays && Number( leftDays ) === 0 ){
                code.splice(0,1);
            }
            return {
                d:  leftDays 
                ,h: leftHours  
                ,m: leftMinutes 
                ,s: leftSeconds 
                ,code
            }
        }else{
            return false;
        }
    }else{
        throw new ReferenceError("the params must be required");  
    }
}

$leftDate._checkTime = _checkTime;

/* 转换时间戳
    返回
    {
       year:  Number
      ,month: String || Number
      ,date: String || Number
      ,hours: String || Number
      ,minutes: String || Number
      ,seconds: String || Number
      ,format: String -> "2019-10-20 03:20:50"
      ,_date: Date Object
      ,_timestamp: Number
    }
*/
function $formatDate( dateParams ){
	const dateType = $toClass( dateParams );

	let dateObj;
	if( dateType === "Number"
	  || dateType === "String"
	){
		dateObj = new Date( dateParams );
	}else if( dateType === "Date" ) {
		dateObj = dateParams;
	}else{
		throw TypeError("the dateParams type must be [String,Number,Date]");
	}
	const year = _checkTime( dateObj.getFullYear() );
	const month = _checkTime( dateObj.getMonth() + 1 )
	const date = _checkTime( dateObj.getDate() );
	const hours = _checkTime( dateObj.getHours() );
	const minutes = _checkTime( dateObj.getMinutes() );
	const seconds = _checkTime( dateObj.getSeconds() );
	const format = `${ year }-${ month }-${ date } ${ hours }:${ minutes }:${ seconds }`;
	return {
		year
		,month
		,date
		,hours
		,minutes
		,seconds
		,format
		,_date: dateObj
		,_timestamp: dateObj.getTime()
	};
}



module.exports = {
	$regExp
	,$copy
	,$toClass
	,$trimAll
    ,$drawCode
    ,$leftDate
    /* 路由 */
    ,$url
    ,$back
    /* http请求 */
    ,$get
    ,$post
    ,$put 
    ,$delete 
    ,$request
   
    /* 对话提示 */
    ,$log
    ,$alert
    ,$confirm
    ,$fail
	/* 转换时间戳对象 */
    ,$formatDate
	,$to
}

